<template>
    <transition name="msgbox-fade">
        <div
                class="el-message-box__wrapper"
                tabindex="-1"
                v-show="visible"
                @click.self="handleWrapperClick"
                role="dialog"
                aria-modal="true"
                :aria-label="title || 'dialog'">
            <div class="el-message-box" :class="[customClass, center && 'el-message-box--center']">
                <div class="el-message-box__header" v-if="title !== null">
                    <div class="el-message-box__title">
                        <div
                                :class="['el-message-box__status', icon]"
                                v-if="icon && center">
                        </div>
                        <span>{{ title }}</span>
                    </div>
                    <button
                            type="button"
                            class="el-message-box__headerbtn"
                            aria-label="Close"
                            v-if="showClose"
                            @click="handleAction(distinguishCancelAndClose ? 'close' : 'cancel')"
                            @keydown.enter="handleAction(distinguishCancelAndClose ? 'close' : 'cancel')">
                        <i class="el-message-box__close el-icon-close"></i>
                    </button>
                </div>
                <div class="el-message-box__content">
                    <div class="el-message-box__container">
                        <div
                                :class="['el-message-box__status', icon]"
                                v-if="icon && !center && message !== ''">
                        </div>
                        <div class="el-message-box__message" v-if="message !== ''">
                            <slot>
                                <p v-if="!dangerouslyUseHTMLString">{{ message }}</p>
                                <p v-else v-html="message"></p>
                            </slot>
                        </div>
                    </div>
                    <div class="el-message-box__input" v-show="showInput">
                        <el-input
                                v-model="inputValue"
                                :type="inputType"
                                @keydown.enter.native="handleInputEnter"
                                :placeholder="inputPlaceholder"
                                ref="input"></el-input>
                        <div class="el-message-box__errormsg"
                             :style="{ visibility: !!editorErrorMessage ? 'visible' : 'hidden' }">{{ editorErrorMessage
                            }}
                        </div>
                    </div>
                </div>
                <div class="el-message-box__btns">
                    <el-button
                            :loading="cancelButtonLoading"
                            :class="[ cancelButtonClasses ]"
                            v-if="showCancelButton"
                            :round="roundButton"
                            size="small"
                            @click.native="handleAction('cancel')"
                            @keydown.enter="handleAction('cancel')">
                        {{ cancelButtonText || t('el.messagebox.cancel') }}
                    </el-button>
                    <el-button
                            :loading="confirmButtonLoading"
                            ref="confirm"
                            :class="[ confirmButtonClasses ]"
                            v-show="showConfirmButton"
                            :round="roundButton"
                            size="small"
                            @click.native="handleAction('confirm')"
                            @keydown.enter="handleAction('confirm')">
                        {{ confirmButtonText || t('el.messagebox.confirm') }}
                    </el-button>
                </div>
            </div>
        </div>
    </transition>
</template>

<script type="text/babel">
    import Popup from 'element-ui/src/utils/popup';
    import Locale from 'element-ui/src/mixins/locale';
    import ElInput from 'element-ui/packages/input';
    import ElButton from 'element-ui/packages/button';
    import {addClass, removeClass} from 'element-ui/src/utils/dom';
    import {t} from 'element-ui/src/locale';
    import Dialog from 'element-ui/src/utils/aria-dialog';

    let messageBox;
    let typeMap = {
        success: 'success',
        info: 'info',
        warning: 'warning',
        error: 'error'
    };

    export default {
        mixins: [Popup, Locale],

        props: {
            modal: {
                default: true
            },
            lockScroll: {
                default: true
            },
            showClose: {
                type: Boolean,
                default: true
            },
            closeOnClickModal: {
                default: true
            },
            closeOnPressEscape: {
                default: true
            },
            closeOnHashChange: {
                default: true
            },
            center: {
                default: false,
                type: Boolean
            },
            roundButton: {
                default: false,
                type: Boolean
            }
        },

        components: {
            ElInput,
            ElButton
        },

        computed: {
            icon() {
                const {type, iconClass} = this;
                return iconClass || (type && typeMap[type] ? `el-icon-${ typeMap[type] }` : '');
            },

            confirmButtonClasses() {
                return `el-button--primary ${ this.confirmButtonClass }`;
            },
            cancelButtonClasses() {
                return `${ this.cancelButtonClass }`;
            }
        },

        methods: {
            getSafeClose() {
                const currentId = this.uid;
                return () => {
                    this.$nextTick(() => {
                        if (currentId === this.uid) this.doClose();
                    });
                };
            },
            doClose() {
                if (!this.visible) return;
                this.visible = false;
                this._closing = true;

                this.onClose && this.onClose();
                messageBox.closeDialog(); // 解绑
                if (this.lockScroll) {
                    setTimeout(this.restoreBodyStyle, 200);
                }
                this.opened = false;
                this.doAfterClose();
                setTimeout(() => {
                    if (this.action) this.callback(this.action, this);
                });
            },

            handleWrapperClick() {
                if (this.closeOnClickModal) {
                    this.handleAction(this.distinguishCancelAndClose ? 'close' : 'cancel');
                }
            },

            handleInputEnter() {
                if (this.inputType !== 'textarea') {
                    return this.handleAction('confirm');
                }
            },

            handleAction(action) {
                if (this.$type === 'prompt' && action === 'confirm' && !this.validate()) {
                    return;
                }
                this.action = action;
                if (typeof this.beforeClose === 'function') {
                    this.close = this.getSafeClose();
                    this.beforeClose(action, this, this.close);
                } else {
                    this.doClose();
                }
            },

            validate() {
                if (this.$type === 'prompt') {
                    const inputPattern = this.inputPattern;
                    if (inputPattern && !inputPattern.test(this.inputValue || '')) {
                        this.editorErrorMessage = this.inputErrorMessage || t('el.messagebox.error');
                        addClass(this.getInputElement(), 'invalid');
                        return false;
                    }
                    const inputValidator = this.inputValidator;
                    if (typeof inputValidator === 'function') {
                        const validateResult = inputValidator(this.inputValue);
                        if (validateResult === false) {
                            this.editorErrorMessage = this.inputErrorMessage || t('el.messagebox.error');
                            addClass(this.getInputElement(), 'invalid');
                            return false;
                        }
                        if (typeof validateResult === 'string') {
                            this.editorErrorMessage = validateResult;
                            addClass(this.getInputElement(), 'invalid');
                            return false;
                        }
                    }
                }
                this.editorErrorMessage = '';
                removeClass(this.getInputElement(), 'invalid');
                return true;
            },
            getFirstFocus() {
                const btn = this.$el.querySelector('.el-message-box__btns .el-button');
                const title = this.$el.querySelector('.el-message-box__btns .el-message-box__title');
                return btn || title;
            },
            getInputElement() {
                const inputRefs = this.$refs.input.$refs;
                return inputRefs.input || inputRefs.textarea;
            },
            handleClose() {
                this.handleAction('close');
            }
        },

        watch: {
            inputValue: {
                immediate: true,
                handler(val) {
                    this.$nextTick(_ => {
                        if (this.$type === 'prompt' && val !== null) {
                            this.validate();
                        }
                    });
                }
            },

            visible(val) {
                if (val) {
                    this.uid++;
                    if (this.$type === 'alert' || this.$type === 'confirm') {
                        this.$nextTick(() => {
                            this.$refs.confirm.$el.focus();
                        });
                    }
                    this.focusAfterClosed = document.activeElement;
                    messageBox = new Dialog(this.$el, this.focusAfterClosed, this.getFirstFocus());
                }

                // prompt
                if (this.$type !== 'prompt') return;
                if (val) {
                    setTimeout(() => {
                        if (this.$refs.input && this.$refs.input.$el) {
                            this.getInputElement().focus();
                        }
                    }, 500);
                } else {
                    this.editorErrorMessage = '';
                    removeClass(this.getInputElement(), 'invalid');
                }
            }
        },

        mounted() {
            this.$nextTick(() => {
                if (this.closeOnHashChange) {
                    window.addEventListener('hashchange', this.close);
                }
            });
        },

        beforeDestroy() {
            if (this.closeOnHashChange) {
                window.removeEventListener('hashchange', this.close);
            }
            setTimeout(() => {
                messageBox.closeDialog();
            });
        },

        data() {
            return {
                uid: 1,
                title: undefined,
                message: '',
                type: '',
                iconClass: '',
                customClass: '',
                showInput: false,
                inputValue: null,
                inputPlaceholder: '',
                inputType: 'text',
                inputPattern: null,
                inputValidator: null,
                inputErrorMessage: '',
                showConfirmButton: true,
                showCancelButton: false,
                action: '',
                confirmButtonText: '',
                cancelButtonText: '',
                confirmButtonLoading: false,
                cancelButtonLoading: false,
                confirmButtonClass: '',
                confirmButtonDisabled: false,
                cancelButtonClass: '',
                editorErrorMessage: null,
                callback: null,
                dangerouslyUseHTMLString: false,
                focusAfterClosed: null,
                isOnComposition: false,
                distinguishCancelAndClose: false
            };
        }
    };
</script>
